Implement "fuzzy" key binding lookups; allow matches on key and level but
authorOwen Taylor <otaylor@redhat.com>
Thu, 21 Feb 2002 17:14:10 +0000 (17:14 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Thu, 21 Feb 2002 17:14:10 +0000 (17:14 +0000)
Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>

        * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
        allow matches on key and level but not group. Also, implement
        ignoring "consumed modifiers correctly."

        * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
        GtkKeyHash.

        * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings

        * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
        the group for key release events as well as key press events.

        * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
        Rename unused_modifiers to consumed_modifiers, make the docs and
        non-Xkb implementation match the Xkb implementation.

        * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
        doc and parameter name changes.

        * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
        XkbTranslateKeyCode doesn't handle LockMask, we need to handle
        it ourselves.

        * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
        <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
        to allow dealing with ISO_Left_Tab.

        * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
        gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
        Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
        or <Shift>Tab both are equivalent as a binding specifier.)

        * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
        GTK_RUN_ACTION, so you can bind an accelerator to it.

        * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call
        gdk_unicode_to_keyval on the mnemonic character.

        * tests/testgtk.c: Add a test for the new fuzzy key binding matching.

34 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/ChangeLog
docs/reference/gdk/tmpl/keys.sgml
docs/reference/gtk/Makefile.am
gdk/gdkkeys.h
gdk/linux-fb/gdkkeyboard-fb.c
gdk/win32/gdkkeys-win32.c
gdk/x11/gdkevents-x11.c
gdk/x11/gdkkeys-x11.c
gtk/Makefile.am
gtk/gtkaccelgroup.c
gtk/gtkbindings.c
gtk/gtkbindings.h
gtk/gtkbutton.c
gtk/gtkcombo.c
gtk/gtkdebug.h
gtk/gtkkeyhash.c [new file with mode: 0644]
gtk/gtkkeyhash.h [new file with mode: 0644]
gtk/gtklabel.c
gtk/gtkmain.c
gtk/gtknotebook.c
gtk/gtkpaned.c
gtk/gtkscrolledwindow.c
gtk/gtktextview.c
gtk/gtkwidget.c
gtk/gtkwindow.c
gtk/gtkwindow.h
tests/testgtk.c

index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index bd33c02399b32e7a12bfcecc8a2f15a32c8e142a..856a5c5553e812c803eb0a13a7270f3e2d609d95 100644 (file)
@@ -1,3 +1,45 @@
+Wed Feb 20 14:26:47 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtkkeyhash.[ch]: Implement "fuzzy" key binding lookups;
+       allow matches on key and level but not group. Also, implement 
+       ignoring "consumed modifiers correctly."
+
+       * gtk/gtkaccelgroup.c gtk/gtkbindings.c: Convert to using
+       GtkKeyHash.
+       
+       * gtk/gtkdebug.h gtk/gtkmain.c: Support GTK_DEBUG=keybindings
+
+       * gdk/x11/gdkevents-x11.c (gdk_event_translate): Fill in
+       the group for key release events as well as key press events.
+
+       * gdk/gdkkeys.h gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): 
+       Rename unused_modifiers to consumed_modifiers, make the docs and
+       non-Xkb implementation match the Xkb implementation.
+
+       * gdk/linux-fb/gdkkeyboard-fb.c gdk/win32/gdkkeys-win32.c: Propagate
+       doc and parameter name changes.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state):
+       XkbTranslateKeyCode doesn't handle LockMask, we need to handle
+       it ourselves.
+
+       * gdk/x11/gdkkeys-x11.c (gdk_keymap_translate_keyboard_state): Force
+       <Shift>Tab to give GDK_ISO_Left_Tab, since we need consistency
+       to allow dealing with ISO_Left_Tab.
+       
+       * gtk/gtkwindow.c gtk/gtktextview.c gtk/gtkscrolledwindow.c
+       gtk/gtkpaned.c gtk/gtkcombo.c  gtk/gtknotebook.c:
+       Remove inappropriate uses of GDK_ISO_Left_Tab. (GDK_ISO_Left_Tab
+       or <Shift>Tab both are equivalent as a binding specifier.)
+
+       * gtk/gtkbutton.c (gtk_button_class_init): Make ::activate
+       GTK_RUN_ACTION, so you can bind an accelerator to it.
+
+       * gtk/gtklabel.c (gtk_label_set_uline_text_internal): Call 
+       gdk_unicode_to_keyval on the mnemonic character.
+
+       * tests/testgtk.c: Add a test for the new fuzzy key binding matching.
+
 2002-02-21  jacob berkman  <jacob@ximian.com>
 
        * gtk/theme-bits/Makefile.am (EXTRA_DIST): inconsitent files are
index e051435e9f58e514e8a5f00685c2552c88c7329c..165481dbcbc7151cd0fd7ddc940e4b337b9f88a1 100644 (file)
@@ -1,3 +1,7 @@
+Thu Feb 21 12:11:42 2002  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/Makefile.am (IGNORE_HFILES): Add gtkkeyhash.h
+
 2002-02-20  Sven Neumann  <sven@gimp.org>
 
        * gtk/gtk-sections.txt
index c1f2d482e9a73daa2ff1449eee348a5823597c17..360733587e4a08782d4df5e9be03c7770070827d 100644 (file)
@@ -139,8 +139,10 @@ be mapped to a keyval.
 @keyval: 
 @effective_group: 
 @level: 
-@unused_modifiers: 
+@consumed_modifiers: 
 @Returns: 
+<!-- # Unused Parameters # -->
+@unused_modifiers: 
 
 
 <!-- ##### FUNCTION gdk_keymap_get_entries_for_keyval ##### -->
index 3c375315aaf8b414f4eaae4d8b0e4dc93da53912..6eccf150dc2432eb2211b6a9d733b420da58cc74 100644 (file)
@@ -33,6 +33,7 @@ IGNORE_HFILES=                        \
        gtkhsv.h                \
        gtkimmodule.h           \
        gtkintl.h               \
+       gtkkeyhash.h            \
        gtkmarshal.h            \
        gtkprivate.h            \
        gtktreeprivate.h        \
index e08af315f8405c71236df923c9558bf5863dc52a..c884b964f350b81272cc653df7fdc406675bba14 100644 (file)
@@ -88,7 +88,7 @@ gboolean       gdk_keymap_translate_keyboard_state (GdkKeymap           *keymap,
                                                    guint               *keyval,
                                                    gint                *effective_group,
                                                    gint                *level,
-                                                   GdkModifierType     *unused_modifiers);
+                                                   GdkModifierType     *consumed_modifiers);
 gboolean       gdk_keymap_get_entries_for_keyval   (GdkKeymap           *keymap,
                                                    guint                keyval,
                                                    GdkKeymapKey       **keys,
index 1f7d75dcbd9de9a9fed7091c76d9a2bb8e7c07f8..625d516c9cc1c9af7de7c41204fb57b96aed66db 100644 (file)
@@ -61,7 +61,7 @@ struct _GdkFBKeyboardDevice {
                                        guint               *keyval,
                                        gint                *effective_group,
                                        gint                *level,
-                                       GdkModifierType     *unused_modifiers);
+                                       GdkModifierType     *consumed_modifiers);
   gboolean (*get_entries_for_keyval)   (GdkFBKeyboard       *kb,
                                        guint                keyval,
                                        GdkKeymapKey       **keys,
@@ -89,7 +89,7 @@ static gboolean xlate_translate       (GdkFBKeyboard       *kb,
                                       guint               *keyval,
                                       gint                *effective_group,
                                       gint                *level,
-                                      GdkModifierType     *unused_modifiers);
+                                      GdkModifierType     *consumed_modifiers);
 static gboolean xlate_get_for_keyval  (GdkFBKeyboard       *kb,
                                       guint                keyval,
                                       GdkKeymapKey       **keys,
@@ -111,7 +111,7 @@ static gboolean raw_translate       (GdkFBKeyboard       *kb,
                                     guint               *keyval,
                                     gint                *effective_group,
                                     gint                *level,
-                                    GdkModifierType     *unused_modifiers);
+                                    GdkModifierType     *consumed_modifiers);
 static gboolean raw_get_for_keyval  (GdkFBKeyboard       *kb,
                                     guint                keyval,
                                     GdkKeymapKey       **keys,
@@ -335,13 +335,13 @@ gdk_keymap_lookup_key (GdkKeymap          *keymap,
  * @keyval: return location for keyval
  * @effective_group: return location for effective group
  * @level: return location for level
- * @unused_modifiers: return location for modifiers that didn't affect the group or level
+ * @consumed_modifiers: return location for modifiers that were used to determine the group or level
  * 
  *
  * Translates the contents of a #GdkEventKey into a keyval, effective
- * group, and level. Modifiers that didn't affect the translation and
- * are thus available for application use are returned in
- * @unused_modifiers.  See gdk_keyval_get_keys() for an explanation of
+ * group, and level. Modifiers that affected the translation and
+ * are thus unavailable for application use are returned in
+ * @consumed_modifiers.  See gdk_keyval_get_keys() for an explanation of
  * groups and levels.  The @effective_group is the group that was
  * actually used for the translation; some keys such as Enter are not
  * affected by the active keyboard group. The @level is derived from
@@ -358,7 +358,7 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
                                      guint           *keyval,
                                      gint            *effective_group,
                                      gint            *level,
-                                     GdkModifierType *unused_modifiers)
+                                     GdkModifierType *consumed_modifiers)
 {
   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
   g_return_val_if_fail (group < 4, FALSE);
@@ -370,7 +370,7 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
                                                         keyval,
                                                         effective_group,
                                                         level,
-                                                        unused_modifiers);
+                                                        consumed_modifiers);
 }
 
 static void
@@ -934,7 +934,7 @@ xlate_translate (GdkFBKeyboard       *kb,
                 guint               *keyval,
                 gint                *effective_group,
                 gint                *level,
-                GdkModifierType     *unused_modifiers)
+                GdkModifierType     *consumed_modifiers)
 {
   g_warning ("xlate_translate() NIY");
   return FALSE;
@@ -1445,7 +1445,7 @@ raw_translate (GdkFBKeyboard       *kb,
                 guint               *keyval,
                 gint                *effective_group,
                 gint                *level,
-                GdkModifierType     *unused_modifiers)
+                GdkModifierType     *consumed_modifiers)
 {
   g_warning ("raw_translate() NIY");
   return FALSE;
index 91f73770b3ec4f1795e2206f3c4ef1b37ee7792a..b28bd7b22b8e73a580027339edd818178da2cb0e 100644 (file)
@@ -261,13 +261,13 @@ gdk_keymap_lookup_key (GdkKeymap          *keymap,
  * @keyval: return location for keyval
  * @effective_group: return location for effective group
  * @level: return location for level
- * @unused_modifiers: return location for modifiers that didn't affect the group or level
+ * @consumed_modifiers: return location for modifiers that were used to determine the group or level
  * 
  *
  * Translates the contents of a #GdkEventKey into a keyval, effective
- * group, and level. Modifiers that didn't affect the translation and
- * are thus available for application use are returned in
- * @unused_modifiers.  See gdk_keyval_get_keys() for an explanation of
+ * group, and level. Modifiers that affected the translation and
+ * are thus unavailable for application use are returned in
+ * @consumed_modifiers.  See gdk_keyval_get_keys() for an explanation of
  * groups and levels.  The @effective_group is the group that was
  * actually used for the translation; some keys such as Enter are not
  * affected by the active keyboard group. The @level is derived from
@@ -284,7 +284,7 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
                                      guint           *keyval,
                                      gint            *effective_group,
                                      gint            *level,
-                                     GdkModifierType *unused_modifiers)
+                                     GdkModifierType *consumed_modifiers)
 {
   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
   g_return_val_if_fail (group < 4, FALSE);
index d72b98b5c512cf5db52eca0c005946897f1dfd58..2c660462079d6e439bbbf4218f9839556a6e5abd 100644 (file)
@@ -679,6 +679,8 @@ gdk_event_translate (GdkEvent *event,
       event->key.length = 0;
       event->key.string = NULL;
       
+      event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
+
       break;
       
     case ButtonPress:
index 139ab9fb7f821e30355011932dc5107edd488a4c..e6eb7e125c548945b0584269c9b32d18c518fa8b 100644 (file)
@@ -735,13 +735,13 @@ MyEnhancedXkbTranslateKeyCode(register XkbDescPtr     xkb,
  * @keyval: return location for keyval
  * @effective_group: return location for effective group
  * @level: return location for level
- * @unused_modifiers: return location for modifiers that didn't affect the group or level
+ * @consumed_modifiers: return location for modifiers that were used to determine the group or level
  * 
  *
  * Translates the contents of a #GdkEventKey into a keyval, effective
- * group, and level. Modifiers that didn't affect the translation and
- * are thus available for application use are returned in
- * @unused_modifiers.  See gdk_keyval_get_keys() for an explanation of
+ * group, and level. Modifiers that affected the translation and
+ * are thus unavailable for application use are returned in
+ * @consumed_modifiers.  See gdk_keyval_get_keys() for an explanation of
  * groups and levels.  The @effective_group is the group that was
  * actually used for the translation; some keys such as Enter are not
  * affected by the active keyboard group. The @level is derived from
@@ -758,9 +758,10 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
                                      guint           *keyval,
                                      gint            *effective_group,
                                      gint            *level,
-                                     GdkModifierType *unused_modifiers)
+                                     GdkModifierType *consumed_modifiers)
 {
   KeySym tmp_keyval = NoSymbol;
+  guint tmp_modifiers;
 
   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
   g_return_val_if_fail (group < 4, FALSE);
@@ -771,8 +772,8 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
     *effective_group = 0;
   if (level)
     *level = 0;
-  if (unused_modifiers)
-    *unused_modifiers = state;
+  if (consumed_modifiers)
+    *consumed_modifiers = 0;
 
   update_keyrange ();
   
@@ -792,13 +793,18 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
       MyEnhancedXkbTranslateKeyCode (xkb,
                                      hardware_keycode,
                                      state,
-                                     unused_modifiers,
+                                     &tmp_modifiers,
                                      &tmp_keyval,
                                      effective_group,
                                      level);
 
-      if (keyval)
-        *keyval = tmp_keyval;
+      if (state & ~tmp_modifiers & LockMask)
+       tmp_keyval = gdk_keyval_to_upper (tmp_keyval);
+
+      /* We need to augment the consumed modifiers with LockMask, since
+       * we handle that ourselves, and also with the group bits
+       */
+      tmp_modifiers |= LockMask | 1 << 13 | 1 << 14;
     }
   else
 #endif
@@ -819,14 +825,7 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
       tmp_keyval = XKeycodeToKeysym (gdk_display, hardware_keycode,
                                      group * keysyms_per_keycode + shift_level);
       
-      if (keyval)
-        *keyval = tmp_keyval;
-
-      if (unused_modifiers)
-        {
-          *unused_modifiers = state;
-          *unused_modifiers &= ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | group_switch_mask);
-        }
+      tmp_modifiers = GDK_SHIFT_MASK | GDK_LOCK_MASK | group_switch_mask;
       
       if (effective_group)
         *effective_group = (state & group_switch_mask) ? 1 : 0;
@@ -835,6 +834,23 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
         *level = shift_level;
     }
 
+  /* GDK_ISO_Left_Tab, as usually configured through XKB, really messes
+   * up the whole idea of "consumed modifiers" because shift is consumed.
+   * However, <shift>Tab is not _consistently_ GDK_ISO_Left_Tab, so people
+   * can't bind to GDK_ISO_Left_Tab instead. So, we force consistency here.
+   */
+  if (tmp_keyval == GDK_Tab && (tmp_modifiers & GDK_SHIFT_MASK == 0))
+    {
+      tmp_keyval = GDK_ISO_Left_Tab;
+      tmp_modifiers |= GDK_SHIFT_MASK;
+    }
+
+  if (consumed_modifiers)
+    *consumed_modifiers = tmp_modifiers;
+                               
+  if (keyval)
+    *keyval = tmp_keyval;
+
   return tmp_keyval != NoSymbol;
 }
 
index 57701300fd795e66c4668eacf75508b92e0f3e81..779bea0c9c7dbcde79d17ac8bff2f25655276136 100644 (file)
@@ -308,6 +308,8 @@ gtk_c_sources = @STRIP_BEGIN@   \
        gtkinvisible.c          \
        gtkitem.c               \
        gtkitemfactory.c        \
+       gtkkeyhash.c            \
+       gtkkeyhash.h            \
        gtklabel.c              \
        gtklayout.c             \
        gtklist.c               \
index 8ee2a8ba6bfba9d76a57a30e206fa6b04a6ef379..3f15a9e6e0e0814afde5b88a2d52dc8f42c9620c 100644 (file)
@@ -714,7 +714,7 @@ gtk_accel_group_from_accel_closure (GClosure *closure)
 
   g_return_val_if_fail (closure != NULL, NULL);
 
-  /* a few remarks on wat we do here. in general, we need a way to reverse lookup
+  /* a few remarks on what we do here. in general, we need a way to reverse lookup
    * accel_groups from closures that are being used in accel groups. this could
    * be done e.g via a hashtable. it is however cheaper (memory wise) to just
    * use the invalidation notifier on the closure itself (which we need to install
index 676ff3ed8df904c162f7f6e02ce99e3837f2f101..95ae875d87a15735711c235235ba96e0bb14a82b 100644 (file)
@@ -29,7 +29,9 @@
 
 #include <string.h>
 #include <stdarg.h>
+#include <gdkkeysyms.h>
 #include "gtkbindings.h"
+#include "gtkkeyhash.h"
 #include "gtksignal.h"
 #include "gtkwidget.h"
 #include "gtkrc.h"
@@ -49,6 +51,7 @@ typedef struct {
 
 /* --- variables --- */
 static GHashTable      *binding_entry_hash_table = NULL;
+static GSList           *binding_key_hashes = NULL;
 static GSList          *binding_set_list = NULL;
 static const gchar     *key_class_binding_set = "gtk-class-binding-set";
 static GQuark           key_id_class_binding_set = 0;
@@ -107,11 +110,81 @@ binding_entries_compare (gconstpointer  a,
   return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
 }
 
+static void
+binding_key_hash_insert_entry (GtkKeyHash      *key_hash,
+                              GtkBindingEntry *entry)
+{
+  guint keyval = entry->keyval;
+  
+  /* We store lowercased accelerators. To deal with this, if <Shift>
+   * was specified, uppercase.
+   */
+  if (entry->modifiers & GDK_SHIFT_MASK)
+    {
+      if (keyval == GDK_Tab)
+       keyval = GDK_ISO_Left_Tab;
+      else
+       keyval = gdk_keyval_to_upper (keyval);
+    }
+  
+  _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
+}
+
+static void
+binding_key_hash_destroy (gpointer data)
+{
+  GtkKeyHash *key_hash = data;
+  
+  binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
+  _gtk_key_hash_free (key_hash);
+}
+
+static void
+insert_entries_into_key_hash (gpointer key,
+                             gpointer value,
+                             gpointer data)
+{
+  GtkKeyHash *key_hash = data;
+  GtkBindingEntry *entry = value;
+
+  for (; entry; entry = entry->hash_next)
+    binding_key_hash_insert_entry (key_hash, entry);
+}
+
+static GtkKeyHash *
+binding_key_hash_for_keymap (GdkKeymap *keymap)
+{
+  static GQuark key_hash_quark = 0;
+  GtkKeyHash *key_hash;
+
+  if (!key_hash_quark)
+    key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
+  
+  key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
+
+  if (!key_hash)
+    {
+      key_hash = _gtk_key_hash_new (keymap, NULL);
+      g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
+
+      if (binding_entry_hash_table)
+       g_hash_table_foreach (binding_entry_hash_table,
+                             insert_entries_into_key_hash,
+                             key_hash);
+
+      binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
+    }
+
+  return key_hash;
+}
+
+
 static GtkBindingEntry*
 binding_entry_new (GtkBindingSet  *binding_set,
                   guint           keyval,
                   GdkModifierType modifiers)
 {
+  GSList *tmp_list;
   GtkBindingEntry *entry;
   
   if (!binding_entry_hash_table)
@@ -132,6 +205,12 @@ binding_entry_new (GtkBindingSet  *binding_set,
   if (entry->hash_next)
     g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
   g_hash_table_insert (binding_entry_hash_table, entry, entry);
+
+  for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
+    {
+      GtkKeyHash *key_hash = tmp_list->data;
+      binding_key_hash_insert_entry (key_hash, entry);
+    }
   
   return entry;
 }
@@ -167,6 +246,7 @@ binding_entry_destroy (GtkBindingEntry *entry)
   register GtkBindingEntry *tmp;
   GtkBindingEntry *begin;
   register GtkBindingEntry *last;
+  GSList *tmp_list;
 
   /* unlink from binding set
    */
@@ -214,27 +294,18 @@ binding_entry_destroy (GtkBindingEntry *entry)
       g_hash_table_insert (binding_entry_hash_table, begin, begin);
     }
 
+  for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
+    {
+      GtkKeyHash *key_hash = tmp_list->data;
+      _gtk_key_hash_remove_entry (key_hash, entry);
+    }
+
   entry->destroyed = TRUE;
 
   if (!entry->in_emission)
     binding_entry_free (entry);
 }
 
-static GtkBindingEntry*
-binding_ht_lookup_list (guint           keyval,
-                       GdkModifierType modifiers)
-{
-  GtkBindingEntry lookup_entry = { 0 };
-  
-  if (!binding_entry_hash_table)
-    return NULL;
-  
-  lookup_entry.keyval = keyval;
-  lookup_entry.modifiers = modifiers;
-  
-  return g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
-}
-
 static GtkBindingEntry*
 binding_ht_lookup_entry (GtkBindingSet  *set,
                         guint           keyval,
@@ -835,7 +906,7 @@ gtk_binding_set_add_path (GtkBindingSet          *binding_set,
     }
 }
 
-static inline gboolean
+static gboolean
 binding_match_activate (GSList          *pspec_list,
                        GtkObject       *object,
                        guint            path_length,
@@ -877,20 +948,25 @@ gtk_binding_pattern_compare (gconstpointer new_pattern,
   return np->seq_id < ep->seq_id;
 }
 
-static inline GSList*
-gtk_binding_entries_sort_patterns (GtkBindingEntry    *entries,
-                                  GtkPathType         path_id)
+static GSList*
+gtk_binding_entries_sort_patterns (GSList      *entries,
+                                  GtkPathType  path_id,
+                                  gboolean     is_release)
 {
   GSList *patterns;
 
   patterns = NULL;
-  while (entries)
+  for (; entries; entries = entries->next)
     {
-      register GtkBindingSet *binding_set;
+      GtkBindingEntry *entry = entries->data;
+      GtkBindingSet *binding_set;
       GSList *slist = NULL;
 
-      binding_set = entries->binding_set;
-      binding_set->current = entries;
+      if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
+       continue;
+
+      binding_set = entry->binding_set;
+      binding_set->current = entry;
 
       switch (path_id)
        {
@@ -912,35 +988,19 @@ gtk_binding_entries_sort_patterns (GtkBindingEntry    *entries,
          pspec = slist->data;
          patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
        }
-
-      entries = entries->hash_next;
     }
 
   return patterns;
 }
-      
 
-gboolean
-gtk_bindings_activate (GtkObject      *object,
-                      guint           keyval,
-                      GdkModifierType modifiers)
+static gboolean
+gtk_bindings_activate_list (GtkObject *object,
+                           GSList    *entries,
+                           gboolean   is_release)
 {
-  GtkBindingEntry *entries;
-  GtkWidget *widget;
+  GtkWidget *widget = GTK_WIDGET (object);
   gboolean handled = FALSE;
 
-  g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
-
-  if (!GTK_IS_WIDGET (object))
-    return FALSE;
-
-  widget = GTK_WIDGET (object);
-
-  keyval = gdk_keyval_to_lower (keyval);
-  modifiers = modifiers & BINDING_MOD_MASK ();
-
-  entries = binding_ht_lookup_list (keyval, modifiers);
-
   if (!entries)
     return FALSE;
 
@@ -951,7 +1011,7 @@ gtk_bindings_activate (GtkObject      *object,
       GSList *patterns;
 
       gtk_widget_path (widget, &path_length, &path, &path_reversed);
-      patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET);
+      patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
       g_slist_free (patterns);
       g_free (path);
@@ -965,7 +1025,7 @@ gtk_bindings_activate (GtkObject      *object,
       GSList *patterns;
 
       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
-      patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS);
+      patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
       g_slist_free (patterns);
       g_free (path);
@@ -977,7 +1037,7 @@ gtk_bindings_activate (GtkObject      *object,
       GSList *patterns;
       GtkType class_type;
       
-      patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS);
+      patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
       class_type = GTK_OBJECT_TYPE (object);
       while (class_type && !handled)
        {
@@ -1000,6 +1060,71 @@ gtk_bindings_activate (GtkObject      *object,
   return handled;
 }
 
+gboolean
+gtk_bindings_activate (GtkObject      *object,
+                      guint           keyval,
+                      GdkModifierType modifiers)
+{
+  GSList *entries = NULL;
+  GtkKeyHash *key_hash;
+  gboolean handled = FALSE;
+  gboolean is_release;
+
+  g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
+
+  if (!GTK_IS_WIDGET (object))
+    return FALSE;
+
+  is_release = (BINDING_MOD_MASK () & GDK_RELEASE_MASK) != 0;
+  modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
+
+  key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
+  entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
+
+  handled = gtk_bindings_activate_list (object, entries, is_release);
+
+  g_slist_free (entries);
+
+  return handled;
+}
+
+/**
+ * _gtk_bindings_activate_event:
+ * @object: a #GtkObject (generally must be a widget)
+ * @event: a #GdkEventKey
+ * 
+ * Looks up key bindings for @object to find one matching
+ * @event, and if one was found, activate it.
+ * 
+ * Return value: %TRUE if a matching key binding was found
+ **/
+gboolean
+_gtk_bindings_activate_event (GtkObject      *object,
+                             GdkEventKey    *event)
+{
+  GSList *entries = NULL;
+  GtkKeyHash *key_hash;
+  gboolean handled = FALSE;
+
+  g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
+
+  if (!GTK_IS_WIDGET (object))
+    return FALSE;
+
+  key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
+  entries = _gtk_key_hash_lookup (key_hash,
+                                 event->hardware_keycode,
+                                 event->state & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
+                                 event->group);
+  
+  handled = gtk_bindings_activate_list (object, entries,
+                                       event->type == GDK_KEY_RELEASE);
+
+  g_slist_free (entries);
+
+  return handled;
+}
+
 static guint
 gtk_binding_parse_signal (GScanner       *scanner,
                          GtkBindingSet  *binding_set,
index d5743905595752d361caf14c03e6fa5d50e727bb..a481f23df694c3583fdced745429e0d78848e41d 100644 (file)
@@ -136,7 +136,9 @@ void         gtk_binding_entry_add_signall  (GtkBindingSet  *binding_set,
 guint   gtk_binding_parse_binding      (GScanner       *scanner);
 
 
-void     _gtk_binding_reset_parsed      (void);
+gboolean _gtk_bindings_activate_event (GtkObject   *object,
+                                      GdkEventKey *event);
+void     _gtk_binding_reset_parsed    (void);
 
 #ifdef __cplusplus
 }
index c0d470687418a8db9193537d010d137feb039567..86701f9feed74bef25b7fceffaca0c6cb5272000 100644 (file)
@@ -253,7 +253,7 @@ gtk_button_class_init (GtkButtonClass *klass)
                    GTK_TYPE_NONE, 0);
   button_signals[ACTIVATE] =
     gtk_signal_new ("activate",
-                    GTK_RUN_FIRST,
+                    GTK_RUN_FIRST | GTK_RUN_ACTION,
                     GTK_CLASS_TYPE (object_class),
                     GTK_SIGNAL_OFFSET (GtkButtonClass, activate),
                     _gtk_marshal_VOID__VOID,
index d236801b62627d59a4266eee1a39557363769478..a09b572a84c628c6ca0612083fcfcacd9eac0ee8 100644 (file)
@@ -199,7 +199,6 @@ gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * com
 
   /* completion */
   if ((event->keyval == GDK_Tab ||
-       event->keyval == GDK_ISO_Left_Tab ||
        event->keyval == GDK_KP_Tab) &&
       (event->state & GDK_MOD1_MASK)) 
     {
index 8c7ddd94233f27bb1817b89fbaeaca6633038aa3..7aa18463eeb900ee4a63c12d97f5fa57c599319e 100644 (file)
 #ifndef __GTK_DEBUG_H__
 #define __GTK_DEBUG_H__
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+#include <glib.h>
+
+G_BEGIN_DECLS
 
 typedef enum {
-  GTK_DEBUG_MISC       = 1 << 0,
-  GTK_DEBUG_PLUGSOCKET = 1 << 1,
-  GTK_DEBUG_TEXT       = 1 << 2,
-  GTK_DEBUG_TREE       = 1 << 3,
-  GTK_DEBUG_UPDATES    = 1 << 4
+  GTK_DEBUG_MISC        = 1 << 0,
+  GTK_DEBUG_PLUGSOCKET  = 1 << 1,
+  GTK_DEBUG_TEXT        = 1 << 2,
+  GTK_DEBUG_TREE        = 1 << 3,
+  GTK_DEBUG_UPDATES     = 1 << 4,
+  GTK_DEBUG_KEYBINDINGS = 1 << 5
 } GtkDebugFlag;
 
 #ifdef G_ENABLE_DEBUG
@@ -63,9 +64,6 @@ typedef enum {
 
 GTKVAR guint gtk_debug_flags;
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
+G_END_DECLS
 
 #endif /* __GTK_DEBUG_H__ */
diff --git a/gtk/gtkkeyhash.c b/gtk/gtkkeyhash.c
new file mode 100644 (file)
index 0000000..b904c44
--- /dev/null
@@ -0,0 +1,379 @@
+/* gtkkeyhash.c: Keymap aware matching of key bindings
+ *
+ * GTK - The GIMP Toolkit
+ * Copyright (C) 2002, Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include "gtkdebug.h"
+#include "gtkkeyhash.h"
+
+/* We need to add a ::changed signal to GdkKeyMap to properly deal
+ * with changes to the key map while we are running.
+ */
+#undef HAVE_CHANGED_SIGNAL
+
+typedef struct _GtkKeyHashEntry GtkKeyHashEntry;
+
+struct _GtkKeyHashEntry
+{
+  guint keyval;
+  GdkModifierType modifiers;
+  GdkKeymapKey *keys;
+  gint n_keys;
+  gpointer value;
+};
+
+struct _GtkKeyHash
+{
+  GdkKeymap *keymap;
+  GHashTable *keycode_hash;
+  GHashTable *reverse_hash;
+  GDestroyNotify destroy_notify;
+};
+
+static void
+key_hash_clear_keycode (gpointer key,
+                       gpointer value,
+                       gpointer data)
+{
+  GSList *keys = value;
+  g_slist_free (keys);
+}
+
+static void
+key_hash_insert_entry (GtkKeyHash      *key_hash,
+                      GtkKeyHashEntry *entry)
+{
+  gint i;
+
+  gdk_keymap_get_entries_for_keyval (key_hash->keymap,
+                                    entry->keyval,
+                                    &entry->keys, &entry->n_keys);
+  
+  for (i = 0; i < entry->n_keys; i++)
+    {
+      GSList *old_keys = g_hash_table_lookup (key_hash->keycode_hash,
+                                             GUINT_TO_POINTER (entry->keys[i].keycode));
+      old_keys = g_slist_prepend (old_keys, entry);
+      g_hash_table_insert (key_hash->keycode_hash,
+                          GUINT_TO_POINTER (entry->keys[i].keycode),
+                          old_keys);
+    }
+}
+
+#ifdef HAVE_CHANGED_SIGNAL
+static void
+key_hash_reinsert_entry (gpointer key,
+                        gpointer value,
+                        gpointer data)
+{
+  GtkKeyHashEntry *entry = value;
+  GtkKeyHash *key_hash = data;
+
+  g_free (entry->keys);
+  key_hash_insert_entry (key_hash, entry);
+}
+
+static void
+key_hash_keymap_changed (GdkKeymap  *keymap,
+                        GtkKeyHash *key_hash)
+{
+  /* The keymap changed, so we have to clear and reinsert all our entries
+   */
+  g_hash_table_foreach (key_hash->keycode_hash, key_hash_clear_keycode, NULL);
+
+  /* FIXME: Here we reinsert in random order, but I think we actually have to
+   * insert in the same order as the original order to keep GtkBindingSet happy.
+   */
+  g_hash_table_foreach (key_hash->reverse_hash, key_hash_reinsert_entry, key_hash);
+}
+#endif /* HAVE_CHANGED_SIGNAL */
+
+/**
+ * _gtk_key_hash_new:
+ * @keymap: a #GdkKeymap
+ * @item_destroy_notify: function to be called when items are removed
+ *   from the hash or %NULL.
+ * 
+ * Create a new key hash object for doing binding resolution. 
+ * 
+ * Return value: the newly created object. Free with _gtk_key_hash_free().
+ **/
+GtkKeyHash *
+_gtk_key_hash_new (GdkKeymap      *keymap,
+                  GDestroyNotify  item_destroy_notify)
+{
+  GtkKeyHash *key_hash = g_new (GtkKeyHash, 1);
+
+  key_hash->keymap = keymap;
+#ifdef HAVE_CHANGED_SIGNAL
+  g_signal_connect (keymap, "changed",
+                   G_CALLBACK (key_hash_keymap_changed), key_hash);
+#endif  
+
+  key_hash->keycode_hash = g_hash_table_new (g_direct_hash, NULL);
+  key_hash->reverse_hash = g_hash_table_new (g_direct_hash, NULL);
+  key_hash->destroy_notify = item_destroy_notify;
+
+  return key_hash;
+}
+
+static void
+key_hash_free_entry (GtkKeyHash      *key_hash,
+                    GtkKeyHashEntry *entry)
+{
+  if (key_hash->destroy_notify)
+    (*key_hash->destroy_notify) (entry->value);
+  
+  g_free (entry->keys);
+  g_free (entry);
+}
+
+static void
+key_hash_free_entry_foreach (gpointer key,
+                            gpointer value,
+                            gpointer data)
+{
+  GtkKeyHashEntry *entry = value;
+  GtkKeyHash *key_hash = data;
+
+  key_hash_free_entry (key_hash, entry);
+}
+
+/**
+ * gtk_key_hash_free:
+ * @key_hash: a #GtkKeyHash
+ * 
+ * Destroys a key hash created with gtk_key_hash_new()
+ **/
+void
+_gtk_key_hash_free (GtkKeyHash *key_hash)
+{
+#if HAVE_CHANGED_SIGNAL  
+  g_signal_handlers_disconnect_by_func (key_hash->keymap,
+                                       G_CALLBACK (key_hash_keymap_changed), key_hash);
+#endif
+
+  g_hash_table_foreach (key_hash->keycode_hash, key_hash_clear_keycode, NULL);
+  g_hash_table_foreach (key_hash->reverse_hash, key_hash_free_entry_foreach, key_hash);
+  g_hash_table_destroy (key_hash->keycode_hash);
+  g_hash_table_destroy (key_hash->reverse_hash);
+
+  g_free (key_hash);
+}
+
+/**
+ * _gtk_key_hash_add_entry:
+ * @key_hash: a #GtkKeyHash
+ * @keyval: key symbol for this binding
+ * @modifiers: modifiers for this binding
+ * @value: value to insert in the key hash
+ * 
+ * Inserts a pair of key symbol and modifier mask into the key hash. 
+ **/
+void
+_gtk_key_hash_add_entry (GtkKeyHash      *key_hash,
+                        guint            keyval,
+                        GdkModifierType  modifiers,
+                        gpointer         value)
+{
+  GtkKeyHashEntry *entry = g_new (GtkKeyHashEntry, 1);
+
+  entry->value = value;
+  entry->keyval = keyval;
+  entry->modifiers = modifiers;
+
+  g_hash_table_insert (key_hash->reverse_hash, value, entry);
+  key_hash_insert_entry (key_hash, entry);
+}
+
+/**
+ * _gtk_key_hash_remove_entry:
+ * @key_hash: a #GtkKeyHash
+ * @value: value previously added with _gtk_key_hash_add_entry()
+ * 
+ * Removes a value previously added to the key hash with
+ * _gtk_key_hash_add_entry().
+ **/
+void
+_gtk_key_hash_remove_entry (GtkKeyHash *key_hash,
+                           gpointer    value)
+{
+  GtkKeyHashEntry *entry = g_hash_table_lookup (key_hash->reverse_hash, value);
+  if (entry)
+    {
+      gint i;
+
+      for (i = 0; i < entry->n_keys; i++)
+       {
+         GSList *old_keys = g_hash_table_lookup (key_hash->keycode_hash,
+                                                 GUINT_TO_POINTER (entry->keys[i].keycode));
+
+         GSList *new_keys = g_slist_remove (old_keys, entry);
+         if (old_keys != new_keys)
+           {
+             if (old_keys)
+               g_hash_table_insert (key_hash->keycode_hash,
+                                    GUINT_TO_POINTER (entry->keys[i].keycode),
+                                    old_keys);
+             else
+               g_hash_table_remove (key_hash->keycode_hash,
+                                    GUINT_TO_POINTER (entry->keys[i].keycode));
+           }
+       }
+      
+      g_hash_table_remove (key_hash->reverse_hash, value);
+
+      key_hash_free_entry (key_hash, entry);
+      g_free (entry);
+    }
+}
+
+/**
+ * _gtk_key_hash_lookup:
+ * @key_hash: a #GtkKeyHash
+ * @hardware_keycode: hardware keycode field from a #GdkEventKey
+ * @state: state field from a #GdkEventKey
+ * @group: group field from a #GdkEventKey
+ * 
+ * Looks up the best matching entry or entries in the hash table for
+ * a given event.
+ * 
+ * Return value: A #GSList of all matching entries. If there were exact
+ *  matches, they are returned, otherwise all fuzzy matches are
+ *  returned. (A fuzzy match is a match in keycode and level, but not
+ *  in group.)
+ **/
+GSList *
+_gtk_key_hash_lookup (GtkKeyHash      *key_hash,
+                     guint16          hardware_keycode,
+                     GdkModifierType  state,
+                     gint             group)
+{
+  GSList *keys = g_hash_table_lookup (key_hash->keycode_hash, GUINT_TO_POINTER ((guint)hardware_keycode));
+  GSList *results = NULL;
+  gboolean have_exact = FALSE;
+  guint keyval;
+  gint effective_group;
+  gint level;
+  GdkModifierType consumed_modifiers;
+
+  gdk_keymap_translate_keyboard_state (key_hash->keymap,
+                                      hardware_keycode, state, group,
+                                      &keyval, &effective_group, &level, &consumed_modifiers);
+
+  GTK_NOTE (KEYBINDINGS,
+           g_message ("Looking up keycode = %u, modifiers = 0x%04x,\n"
+                      "    keyval = %u, group = %d, level = %d, consumed_modifiers = 0x%04x",
+                      hardware_keycode, state, keyval, effective_group, level, consumed_modifiers));
+
+  if (keys)
+    {
+      GSList *tmp_list = keys;
+      while (tmp_list)
+       {
+         GtkKeyHashEntry *entry = tmp_list->data;
+
+         if ((entry->modifiers & ~consumed_modifiers) == (state & ~consumed_modifiers))
+           {
+             gint i;
+
+             if (keyval == entry->keyval) /* Exact match */
+               {
+                 GTK_NOTE (KEYBINDINGS,
+                           g_message ("  found exact match, keyval = %u, modifiers = 0x%04x",
+                                      entry->keyval, entry->modifiers));
+                 
+                 if (!have_exact)
+                   {
+                     g_slist_free (results);
+                     results = NULL;
+                   }
+
+                 have_exact = TRUE;
+                 results = g_slist_prepend (results, entry->value);
+               }
+
+             if (!have_exact)
+               {
+                 for (i = 0; i < entry->n_keys; i++)
+                   {
+                     if (entry->keys[i].keycode == hardware_keycode &&
+                         entry->keys[i].level == level) /* Match for all but group */
+                       {
+                         GTK_NOTE (KEYBINDINGS,
+                                   g_message ("  found group = %d, level = %d",
+                                              entry->keys[i].group, entry->keys[i].level));
+                         results = g_slist_prepend (results, entry->value);
+                         break;
+                       }
+                   }
+               }
+           }
+
+         tmp_list = tmp_list->next;
+       }
+    }
+
+  return results;
+}
+
+/**
+ * _gtk_key_hash_lookup_keyval:
+ * @key_hash: a #GtkKeyHash
+ * @event: a #GtkEvent
+ * 
+ * Looks up the best matching entry or entries in the hash table for a
+ * given keyval/modifiers pair. It's better to use
+ * _gtk_key_hash_lookup() if you have the original #GdkEventKey
+ * available.
+ * 
+ * Return value: A #GSList of all matching entries.
+ **/
+GSList *
+_gtk_key_hash_lookup_keyval (GtkKeyHash     *key_hash,
+                            guint           keyval,
+                            GdkModifierType modifiers)
+{
+  GdkKeymapKey *keys;
+  gint n_keys;
+  GSList *results = NULL;
+  
+  /* Find some random keycode for this keycode
+   */
+  gdk_keymap_get_entries_for_keyval (key_hash->keymap, keyval,
+                                    &keys, &n_keys);
+
+  if (n_keys)
+    {
+      GSList *entries = g_hash_table_lookup (key_hash->keycode_hash, GUINT_TO_POINTER (keys[0].keycode));
+
+      while (entries)
+       {
+         GtkKeyHashEntry *entry = entries->data;
+
+         if (entry->keyval == keyval && entry->modifiers == modifiers)
+           results = g_slist_prepend (results, entry->value);
+
+         entries = entries->next;
+       }
+    }
+
+  g_free (keys);
+         
+  return results;
+}
diff --git a/gtk/gtkkeyhash.h b/gtk/gtkkeyhash.h
new file mode 100644 (file)
index 0000000..d02c9f5
--- /dev/null
@@ -0,0 +1,50 @@
+/* gtkkeyhash.h: Keymap aware matching of key bindings
+ *
+ * GTK - The GIMP Toolkit
+ * Copyright (C) 2002, Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_KEY_HASH_H__
+#define __GTK_KEY_HASH_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkKeyHash GtkKeyHash;
+
+GtkKeyHash *_gtk_key_hash_new           (GdkKeymap       *keymap,
+                                        GDestroyNotify   item_destroy_notify);
+void        _gtk_key_hash_add_entry     (GtkKeyHash      *key_hash,
+                                        guint            keyval,
+                                        GdkModifierType  modifiers,
+                                        gpointer         value);
+void        _gtk_key_hash_remove_entry  (GtkKeyHash      *key_hash,
+                                        gpointer         value);
+GSList *    _gtk_key_hash_lookup        (GtkKeyHash      *key_hash,
+                                        guint16          hardware_keycode,
+                                        GdkModifierType  state,
+                                        gint             group);
+GSList *    _gtk_key_hash_lookup_keyval (GtkKeyHash      *key_hash,
+                                        guint            keyval,
+                                        GdkModifierType  modifiers);
+void        _gtk_key_hash_free          (GtkKeyHash      *key_hash);
+
+G_END_DECLS
+
+#endif /* __GTK_KEY_HASH_H__ */
index b587f953cd2e571ba7055cd11173325bcf3daac7..44e259fd431965aae369cc463bf982ee325b0695 100644 (file)
@@ -1827,7 +1827,7 @@ gtk_label_set_uline_text_internal (GtkLabel    *label,
            {
              *pattern_dest++ = '_';
              if (accel_key == GDK_VoidSymbol)
-               accel_key = gdk_keyval_to_lower (c);
+               accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
            }
 
          while (src < next_src)
index 2c3f202173fa58e98ebd98c18e952eef65c9eb37..2b659a467763411e176922af2537b1d2430de6e0 100644 (file)
@@ -155,7 +155,8 @@ static const GDebugKey gtk_debug_keys[] = {
   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
   {"text", GTK_DEBUG_TEXT},
   {"tree", GTK_DEBUG_TREE},
-  {"updates", GTK_DEBUG_UPDATES}
+  {"updates", GTK_DEBUG_UPDATES},
+  {"keybindings", GTK_DEBUG_KEYBINDINGS}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
index 269d796c09b1903fd88f2d0e3a4fbae1084f1dd6..90aef822846ef0c948f84bf7929cb29c1d8ee4ed 100644 (file)
@@ -294,9 +294,6 @@ add_tab_bindings (GtkBindingSet    *binding_set,
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
                                 "move_focus_out", 1,
                                 GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, modifiers,
-                                "move_focus_out", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
 }
 
 static void
index 69141b490fe299af415377e8968b908598bbdee7..85098727c93151860ff15cf60ecac9bc132d7bcc 100644 (file)
@@ -145,9 +145,6 @@ add_tab_bindings (GtkBindingSet    *binding_set,
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
                                 "cycle_handle_focus", 1,
                                 G_TYPE_BOOLEAN, reverse);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, modifiers,
-                                "cycle_handle_focus", 1,
-                                G_TYPE_BOOLEAN, reverse);
 }
 
 static void
index 9f8d4c984c23acec796078eaa969567be2d9a1d0..b22282e687ee3cf91c210e25f24dd934ba7817a3 100644 (file)
@@ -191,9 +191,6 @@ add_tab_bindings (GtkBindingSet    *binding_set,
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
                                 "move_focus_out", 1,
                                 GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, modifiers,
-                                "move_focus_out", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
 }
 
 static void
index 2014aa368af681f38f486b94b7b885eb6deb43c0..328a0c44bec090970872abfa07a116b6f630b2cc 100644 (file)
@@ -933,9 +933,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_CONTROL_MASK,
                                 "move_focus", 1,
                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, GDK_CONTROL_MASK,
-                                "move_focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
   
   gtk_binding_entry_add_signal (binding_set, GDK_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
                                 "move_focus", 1,
@@ -943,9 +940,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
                                 "move_focus", 1,
                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
-                                "move_focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
 }
 
 static void
@@ -3641,8 +3635,7 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
     }
   /* Pass through Tab as literal tab, unless Control is held down */
   else if ((event->keyval == GDK_Tab ||
-            event->keyval == GDK_KP_Tab ||
-            event->keyval == GDK_ISO_Left_Tab) &&
+            event->keyval == GDK_KP_Tab) &&
            !(event->state & GDK_CONTROL_MASK))
     {
       /* If the text isn't editable, move the focus instead */
index 293cd6f625103e9765ba7e8f862011918089cc2a..af9719e7148e9bf61da7ad7941b6fafc0c607940 100644 (file)
@@ -2871,9 +2871,7 @@ gtk_widget_real_key_press_event (GtkWidget         *widget,
   gboolean handled = FALSE;
 
   if (!handled)
-    handled = gtk_bindings_activate (GTK_OBJECT (widget),
-                                    event->keyval,
-                                    event->state);
+    handled = _gtk_bindings_activate_event (GTK_OBJECT (widget), event);
 
   return handled;
 }
@@ -2885,9 +2883,7 @@ gtk_widget_real_key_release_event (GtkWidget         *widget,
   gboolean handled = FALSE;
 
   if (!handled)
-    handled = gtk_bindings_activate (GTK_OBJECT (widget),
-                                    event->keyval,
-                                    event->state | GDK_RELEASE_MASK);
+    handled = _gtk_bindings_activate_event (GTK_OBJECT (widget), event);
 
   return handled;
 }
index 597ca48f4d9d82cce0c416053a6571d3c5eb828c..a031e8bad34aa1d6900d95094d71bbdb3d4d0ffe 100644 (file)
@@ -35,6 +35,7 @@
 #include "gtkwindow.h"
 #include "gtkwindow-decorate.h"
 #include "gtkbindings.h"
+#include "gtkkeyhash.h"
 #include "gtkmain.h"
 #include "gtkiconfactory.h"
 #include "gtkintl.h"
@@ -174,6 +175,7 @@ static void gtk_window_real_activate_default (GtkWindow         *window);
 static void gtk_window_real_activate_focus   (GtkWindow         *window);
 static void gtk_window_move_focus            (GtkWindow         *window,
                                               GtkDirectionType   dir);
+static void gtk_window_keys_changed          (GtkWindow         *window);
 static void gtk_window_read_rcfiles       (GtkWidget         *widget,
                                           GdkEventClient    *event);
 static void gtk_window_paint              (GtkWidget         *widget,
@@ -222,7 +224,12 @@ static void     gtk_window_set_default_size_internal (GtkWindow    *window,
 
 static void     gtk_window_realize_icon               (GtkWindow    *window);
 static void     gtk_window_unrealize_icon             (GtkWindow    *window);
-static void    gtk_window_notify_keys_changed      (GtkWindow    *window);
+
+static void        gtk_window_notify_keys_changed (GtkWindow   *window);
+static gboolean    gtk_window_activate_key        (GtkWindow   *window,
+                                                  GdkEventKey *event);
+static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
+static void        gtk_window_free_key_hash       (GtkWindow   *window);
 
 static GSList      *toplevel_list = NULL;
 static GHashTable  *mnemonic_hash_table = NULL;
@@ -308,9 +315,6 @@ add_tab_bindings (GtkBindingSet    *binding_set,
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
                                 "move_focus", 1,
                                 GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, modifiers,
-                                "move_focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
 }
 
 static void
@@ -388,7 +392,7 @@ gtk_window_class_init (GtkWindowClass *klass)
   klass->activate_default = gtk_window_real_activate_default;
   klass->activate_focus = gtk_window_real_activate_focus;
   klass->move_focus = gtk_window_move_focus;
-  klass->keys_changed = NULL;
+  klass->keys_changed = gtk_window_keys_changed;
   
   /* Construct */
   g_object_class_install_property (gobject_class,
@@ -2901,7 +2905,9 @@ gtk_window_destroy (GtkObject *object)
   if (window->group)
     gtk_window_group_remove_window (window->group, window);
 
-  GTK_OBJECT_CLASS (parent_class)->destroy (object);
+   gtk_window_free_key_hash (window);
+
+   GTK_OBJECT_CLASS (parent_class)->destroy (object);
 }
 
 static gboolean
@@ -3525,13 +3531,10 @@ gtk_window_key_press_event (GtkWidget   *widget,
 
   handled = FALSE;
 
+  /* Check for mnemonics and accelerators
+   */
   if (!handled)
-    handled = gtk_window_mnemonic_activate (window,
-                                           event->keyval,
-                                           event->state);
-
-  if (!handled)
-    handled = gtk_accel_groups_activate (G_OBJECT (window), event->keyval, event->state);
+    handled = gtk_window_activate_key (window, event);
 
   if (!handled)
     {
@@ -5676,3 +5679,183 @@ gtk_window_parse_geometry (GtkWindow   *window,
   
   return result != 0;
 }
+
+typedef void (*GtkWindowKeysForeach) (GtkWindow      *window,
+                                     guint           keyval,
+                                     GdkModifierType modifiers,
+                                     gboolean        is_mnemonic,
+                                     gpointer        data);
+
+static void
+gtk_window_mnemonic_hash_foreach (gpointer key,
+                                 gpointer value,
+                                 gpointer data)
+{
+  struct {
+    GtkWindow *window;
+    GtkWindowKeysForeach func;
+    gpointer func_data;
+  } *info = data;
+
+  GtkWindowMnemonic *mnemonic = value;
+
+  if (mnemonic->window == info->window)
+    (*info->func) (info->window, mnemonic->keyval, info->window->mnemonic_modifier, TRUE, info->func_data);
+}
+
+static void
+gtk_window_keys_foreach (GtkWindow           *window,
+                        GtkWindowKeysForeach func,
+                        gpointer             func_data)
+{
+  GSList *groups;
+
+  struct {
+    GtkWindow *window;
+    GtkWindowKeysForeach func;
+    gpointer func_data;
+  } info;
+
+  info.window = window;
+  info.func = func;
+  info.func_data = func_data;
+
+  g_hash_table_foreach (mnemonic_hash_table,
+                       gtk_window_mnemonic_hash_foreach,
+                       &info);
+
+  groups = gtk_accel_groups_from_object (G_OBJECT (window));
+  while (groups)
+    {
+      GtkAccelGroup *group = groups->data;
+      gint i;
+
+      for (i = 0; i < group->n_accels; i++)
+       {
+         GtkAccelKey *key = &group->priv_accels[i].key;
+         
+         if (key->accel_key)
+           (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
+       }
+      
+      groups = groups->next;
+    }
+}
+
+static void
+gtk_window_keys_changed (GtkWindow *window)
+{
+  gtk_window_free_key_hash (window);
+  gtk_window_get_key_hash (window);
+}
+
+typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
+
+struct _GtkWindowKeyEntry
+{
+  guint keyval;
+  guint modifiers;
+  gboolean is_mnemonic;
+};
+
+static void
+add_to_key_hash (GtkWindow      *window,
+                guint           keyval,
+                GdkModifierType modifiers,
+                gboolean        is_mnemonic,
+                gpointer        data)
+{
+  GtkKeyHash *key_hash = data;
+
+  GtkWindowKeyEntry *entry = g_new (GtkWindowKeyEntry, 1);
+
+  entry->keyval = keyval;
+  entry->modifiers = modifiers;
+  entry->is_mnemonic = is_mnemonic;
+
+  /* GtkAccelGroup stores lowercased accelerators. To deal
+   * with this, if <Shift> was specified, uppercase.
+   */
+  if (modifiers & GDK_SHIFT_MASK)
+    {
+      if (keyval == GDK_Tab)
+       keyval = GDK_ISO_Left_Tab;
+      else
+       keyval = gdk_keyval_to_upper (keyval);
+    }
+  
+  _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
+}
+
+static GtkKeyHash *
+gtk_window_get_key_hash (GtkWindow *window)
+{
+  GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
+  if (key_hash)
+    return key_hash;
+  
+  key_hash = _gtk_key_hash_new (gdk_keymap_get_default(), (GDestroyNotify)g_free);
+  gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
+  g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", key_hash);
+
+  return key_hash;
+}
+
+static void
+gtk_window_free_key_hash (GtkWindow *window)
+{
+  GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
+  if (key_hash)
+    {
+      _gtk_key_hash_free (key_hash);
+      g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", NULL);
+    }
+}
+
+static gboolean
+gtk_window_activate_key (GtkWindow   *window,
+                        GdkEventKey *event)
+{
+  GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
+  GtkWindowKeyEntry *found_entry = NULL;
+
+  if (!key_hash)
+    {
+      gtk_window_keys_changed (window);
+      key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
+    }
+  
+  if (key_hash)
+    {
+      GSList *entries = _gtk_key_hash_lookup (key_hash,
+                                             event->hardware_keycode,
+                                             event->state & gtk_accelerator_get_default_mod_mask (),
+                                             event->group);
+      GSList *tmp_list;
+
+      for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
+       {
+         GtkWindowKeyEntry *entry = tmp_list->data;
+         if (entry->is_mnemonic)
+           {
+             found_entry = entry;
+             break;
+           }
+       }
+      
+      if (!found_entry && entries)
+       found_entry = entries->data;
+
+      g_slist_free (entries);
+    }
+
+  if (found_entry)
+    {
+      if (found_entry->is_mnemonic)
+       return gtk_window_mnemonic_activate (window, found_entry->keyval, found_entry->modifiers);
+      else
+       return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval, found_entry->modifiers);
+    }
+  else
+    return FALSE;
+}
index 2ebfaea759949964bb716f31d2fb95ab2f0eef5d..d6c97376dc14992321df77c4b989e660731d41e1 100644 (file)
@@ -125,7 +125,8 @@ struct _GtkWindowClass
   void     (* activate_focus)          (GtkWindow       *window);
   void     (* activate_default)        (GtkWindow       *window);
   void     (* move_focus)              (GtkWindow       *window,
-                                        GtkDirectionType direction);  
+                                        GtkDirectionType direction);
+  
   void    (*keys_changed)             (GtkWindow       *window);
 };
 
index 7bc2a4710172722be2311a122cae37424d03ef22..216548cf40505068eeb544b51ce130c57f1ddbcb 100644 (file)
@@ -3433,6 +3433,83 @@ create_item_factory (void)
     gtk_widget_destroy (window);
 }
 
+static GtkWidget *
+accel_button_new (GtkAccelGroup *accel_group,
+                 const gchar   *text,
+                 const gchar   *accel)
+{
+  guint keyval;
+  GdkModifierType modifiers;
+  GtkWidget *button;
+  GtkWidget *label;
+
+  gtk_accelerator_parse (accel, &keyval, &modifiers);
+  g_assert (keyval);
+
+  button = gtk_button_new ();
+  gtk_widget_add_accelerator (button, "activate", accel_group,
+                             keyval, modifiers, GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
+
+  label = gtk_accel_label_new (text);
+  gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), button);
+  gtk_widget_show (label);
+  
+  gtk_container_add (GTK_CONTAINER (button), label);
+
+  return button;
+}
+
+static void
+create_key_lookup (void)
+{
+  static GtkWidget *window = NULL;
+  
+  if (!window)
+    {
+      GtkAccelGroup *accel_group = gtk_accel_group_new ();
+      GtkWidget *button;
+      
+      window = gtk_dialog_new_with_buttons ("Key Lookup", NULL, 0,
+                                           GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+                                           NULL);
+
+      /* We have to expand it so the accel labels will draw their labels
+       */
+      gtk_window_set_default_size (GTK_WINDOW (window), 300, -1);
+      
+      gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+      
+      button = gtk_button_new_with_mnemonic ("Button 1 (_a)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = gtk_button_new_with_mnemonic ("Button 2 (_A)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = gtk_button_new_with_mnemonic ("Button 3 (_ф)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = gtk_button_new_with_mnemonic ("Button 4 (_Ф)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = gtk_button_new_with_mnemonic ("Button 6 (_b)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = accel_button_new (accel_group, "Button 7", "<Alt><Shift>b");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = accel_button_new (accel_group, "Button 8", "<Alt>d");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = accel_button_new (accel_group, "Button 9", "<Alt>Cyrillic_ve");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = gtk_button_new_with_mnemonic ("Button 10 (_1)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      button = gtk_button_new_with_mnemonic ("Button 11 (_!)");
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), button, FALSE, FALSE, 0);
+      
+      g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
+      g_signal_connect (window, "response", G_CALLBACK (gtk_object_destroy), NULL);
+
+      gtk_widget_show_all (window);
+    }
+  else
+    gtk_widget_destroy (window);
+}
+
+
 /*
  create_modal_window
  */
@@ -11350,6 +11427,7 @@ struct {
   { "image from drawable", create_get_image },
   { "image", create_image },
   { "item factory", create_item_factory },
+  { "key lookup", create_key_lookup },
   { "labels", create_labels },
   { "layout", create_layout },
   { "list", create_list },